using KlearTweet.Client.Model;

namespace KlearTweet.Client.Search
{
    public class DataProvider
    {
        public readonly EntityCollection Entities = new EntityCollection();

        private readonly Tab.TabController _tabController;
        private readonly Tab.TabHeader _tabHeader;
        private readonly DataContainers.ListView _listView;
        private readonly Initialization.AccountsManager _accountsManager;
        private readonly System.Windows.Threading.DispatcherTimer _timer;
        private WebServices.TwitterSearch _currentTwitterSearch;

        public event Infrastructure.StringEventHandler SearchRequested;


        public DataProvider(Tab.TabController tabController, Tab.TabHeader tabHeader,
            DataContainers.ListView listView, Initialization.AccountsManager accountsManager)
        {
            _tabController = tabController;
            _tabHeader = tabHeader;
            _listView = listView;
            _accountsManager = accountsManager;

            _listView.VerticalScroll += OnVerticalScroll;

            _timer = new System.Windows.Threading.DispatcherTimer();
            _timer.Tick += (s, e) => RequestRefresh();
            _timer.Interval = new System.TimeSpan(0, 0, 1, 0); // TODO: Tune
        }


        public void ShowAccounts()
        {
            _currentTwitterSearch = null;

            Entities.Clear();
            OnEntitiesChanged(true);

            foreach (var entity in _accountsManager.GetAccounts())
                Entities.Add(entity);

            OnEntitiesChanged(false);
        }


        public void SearchAsync(string text)
        {
            OnSearchRequested(text);

            if (text.Trim() == string.Empty)
                _tabController.ShowEmptyPanelAndAccounts();
            else
            {
                // Check if it is a "special search"
                foreach (var account in _accountsManager.GetAccounts())
                {
                    if (text == SearchItem.From(account, SearchItem.FriendsTimeline).SearchText)
                    {
                        OnNewSearch(WebServices.TwitterClient.CreateFriendsTimelineSearch(account));
                        return;
                    }
                    if (text == SearchItem.From(account, SearchItem.UserTimeline).SearchText)
                    {
                        OnNewSearch(WebServices.TwitterClient.CreateUserTimelineSearch(account));
                        return;
                    }
                }

                // Unknown search, just send it as-is
                OnNewSearch(WebServices.TwitterClient.CreateTextSearch(text));
            }
        }


        public void SearchTweetsFromFriends(Account account)
        {
            SearchAsync(SearchItem.From(account, SearchItem.FriendsTimeline).SearchText);
        }

        public void SearchTweetsFromUser(Account account)
        {
            SearchAsync(SearchItem.From(account, SearchItem.UserTimeline).SearchText);
        }


        private void OnSearchRequested(string text)
        {
            var handler = SearchRequested;
            if (handler != null)
                handler(this, new Infrastructure.StringEventArgs(text));
        }



        private void OnNewSearch(WebServices.TwitterSearch twitterSearch)
        {
            _timer.Stop(); // Restart
            _timer.Start();
            _currentTwitterSearch = twitterSearch;

            _tabController.HideEmptyPanel();
            _tabController.FocusOnOmniBox();
            _tabHeader.SetProgressBar(true, false);

            Entities.Clear();
            OnEntitiesChanged(true);

            twitterSearch.SearchCompleted += OnSearchCompleted;
            twitterSearch.RequestNextPage();
        }


        private void OnSearchCompleted(object sender, Infrastructure.EntityEventArgs e)
        {
            if (_currentTwitterSearch != sender)
                return; // Sender is (no longer) the current search, ignore its result

            _tabHeader.SetProgressBar(false, e.Entities == null);

            if (e.Entities == null) // Request failed
                return; // TODO: Show failed reason ?!? Use _header.ActionPanel.SetSearchStatus("reason...");

            Entities.AddRange(e.Entities);

            OnEntitiesChanged(false);
        }


        private void OnEntitiesChanged(bool reset)
        {
            Entities.Sort(); // Keep the entities in the correct order (the added entities can be newer if we refreshed or older if we requested the next page)
            Entities.RaiseCollectionChanged(reset);
        }


        private void RequestRefresh()
        {
            if (_currentTwitterSearch == null)
                return;
            _tabHeader.SetProgressBar(true, false);
            _currentTwitterSearch.RequestRefresh();
        }


        private void OnVerticalScroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
        {
            // Delay the checking until the VerticalOffset has been updated // TODO: Find a better solution
            var timer = new System.Windows.Threading.DispatcherTimer();
            timer.Tick += (s, ev) =>
            {
                timer.Stop();
                if (_currentTwitterSearch == null)
                    return;
                if (_listView.ElementScrollViewer.VerticalOffset + 1500 > _listView.ElementScrollViewer.ExtentHeight) // TODO: Tune number
                {
                    _tabHeader.SetProgressBar(true, false);
                    _currentTwitterSearch.RequestNextPage();
                }
            };
            timer.Interval = new System.TimeSpan(0, 0, 0, 0, 500); // TODO: Tune number
            timer.Start();
        }
    }
}